package com.wekri.wechat4j.api.oauth;

import com.wekri.wechat4j.BaseMsg;
import com.wekri.wechat4j.api.oauth.bean.AuthInfo;
import com.wekri.wechat4j.api.oauth.bean.Scope;
import com.wekri.wechat4j.lang.Language;
import com.wekri.wechat4j.api.user.bean.UserInfo;
import com.wekri.wechat4j.util.HttpUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

/**
 * 微信网页授权
 * <a href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842">微信文档<a/>
 * @author liuweiguo.
 *
 */
public class OAuthApi {

    /**
     * 第二步：通过code换取网页授权access_token
     */
    private static String GET_ACCESS_TOKEN = "https://api.weixin.qq.com/sns/oauth2/access_token";

    /**
     * 第三步：刷新access_token（如果需要）
     */
    private static String GET_REFRESH_TOKEN = "https://api.weixin.qq.com/sns/oauth2/refresh_token";

    /**
     * 第四步：拉取用户信息(需scope为 snsapi_userinfo)
     */
    private static String USER_INFO_GET = "https://api.weixin.qq.com/sns/userinfo";

    /**
     * 检验授权凭证（access_token）是否有效
     */
    private static String CHECK_TOKEN_GET = "https://api.weixin.qq.com/sns/auth";

    /**
     * 若提示“该链接无法访问”，请检查参数是否填写错误，是否拥有scope参数对应的授权作用域权限。
     *
     * @param appId       公众号的唯一标识
     * @param redirectUri 授权后重定向的回调链接地址
     * @param scope       应用授权作用域，snsapi_base （不弹出授权页面，直接跳转，只能获取用户openid），snsapi_userinfo （弹出授权页面，可通过openid拿到昵称、性别、所在地。并且， 即使在未关注的情况下，只要用户授权，也能获取其信息 ）
     * @param state       重定向后会带上state参数，开发者可以填写a-zA-Z0-9的参数值，最多128字节
     * @return
     */
    public String createAuthUrl(String appId, String redirectUri, Scope scope, String state) throws UnsupportedEncodingException {
        return new StringBuilder("https://open.weixin.qq.com/connect/oauth2/authorize?appid=").append(appId)
                .append("&redirect_uri=").append(URLEncoder.encode(redirectUri, "utf-8"))
                .append("&response_type=code&scope=").append(scope.name().toLowerCase())
                .append("&state=").append(state)
                .append("#wechat_redirect").toString();
    }

    /**
     * 通过code换取网页授权access_token
     * <a href=https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842>doc<a/>
     *
     * @param appId  公众号的唯一标识
     * @param secret 公众号的appsecret
     * @param code   填写第一步获取的code参数
     * @return
     */
    public AuthInfo getAccessToken(String appId, String secret, String code) {
        StringBuilder url = new StringBuilder(GET_ACCESS_TOKEN)
                .append("?appid=").append(appId)
                .append("&secret=").append(secret)
                .append("&code=").append(code)
                .append("&grant_type=authorization_code");
        return HttpUtils.get(url.toString(), AuthInfo.class);
    }

    /**
     * 刷新access_token（如果需要）
     * @param appId
     * @param token
     * @return
     */
    public AuthInfo refreshToken(String appId, String token) {
        StringBuilder url = new StringBuilder(GET_REFRESH_TOKEN)
                .append("?appid=").append(appId)
                .append("&grant_type=refresh_token&refresh_token=").append(token);
        return HttpUtils.get(url.toString(), AuthInfo.class);
    }

    /**
     * 拉取用户信息(需scope为 snsapi_userinfo)
     *
     * @param accessToken 网页授权接口调用凭证,注意：此access_token与基础支持的access_token不同
     * @param openid      用户的唯一标识
     * @return
     */
    public UserInfo getUserInfo(String accessToken, String openid) {
        return getUserInfo(accessToken, openid, Language.zh_CN);
    }

    /**
     * 拉取用户信息(需scope为 snsapi_userinfo)
     *
     * @param accessToken 网页授权接口调用凭证,注意：此access_token与基础支持的access_token不同
     * @param openid       用户的唯一标识
     * @param lang         返回国家地区语言版本，zh_CN 简体，zh_TW 繁体，en 英语
     * @return
     */
    public UserInfo getUserInfo(String accessToken, String openid, Language lang) {
        StringBuilder url = new StringBuilder(USER_INFO_GET);
        url.append("?access_token=").append(accessToken)
                .append("&openid=").append(openid)
                .append("&lang=").append(lang);
        return HttpUtils.get(url.toString(), UserInfo.class);
    }

    /**
     * 检验授权凭证（access_token）是否有效
     *
     * @param openid
     * @param accessToken
     * @return
     */
    public BaseMsg checkToken(String openid, String accessToken) {
        StringBuilder url = new StringBuilder(CHECK_TOKEN_GET);
        url.append("?access_token=").append(accessToken)
                .append("&openid=").append(openid);
        return HttpUtils.get(url.toString(), BaseMsg.class);
    }
}
